<%@page import="java.lang.management.ManagementFactory"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="java.text.DecimalFormat"%>
<%@page import="java.text.DecimalFormatSymbols"%>
<%@page import="java.text.NumberFormat"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Locale"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.Properties"%>
<%@page import="java.util.ResourceBundle"%>
<%@page import="java.util.TreeMap"%>
<%@page import="java.util.Iterator"%>
<%@page import="java.io.IOException"%>
<%@page import="java.io.PrintWriter"%>
<%@page import="javax.management.Attribute"%>
<%@page import="javax.management.AttributeList"%>
<%@page import="javax.management.InstanceNotFoundException"%>
<%@page import="javax.management.MBeanServerConnection"%>
<%@page import="javax.management.MBeanServerInvocationHandler"%>
<%@page import="javax.management.ObjectName"%>
<%@page import="javax.management.QueryExp"%>
<%@page import="javax.management.openmbean.CompositeData"%>
<%@page import="javax.management.openmbean.CompositeType"%>
<%@page import="javax.management.openmbean.CompositeDataSupport"%>
<%@page import="javax.management.openmbean.TabularData"%>
<%@page import="javax.management.remote.JMXConnector"%>
<%@page import="wt.access.AccessControlException"%>
<%@page import="wt.intersvrcom.SiteMonitorMBean"%>
<%@page import="wt.jmx.core.MBeanRegistry"%>
<%@page import="wt.jmx.core.MBeanUtilities"%>
<%@page import="wt.jmx.core.SelfAwareMBean"%>
<%@page import="wt.jmx.core.mbeans.Dumper"%>
<%@page import="wt.log4j.LogR"%>
<%@page import="wt.manager.RemoteServerManager"%>
<%@page import="wt.manager.jmx.MethodServerMProxyMBean"%>
<%@page import="wt.method.jmx.JmxConnectInfo"%>
<%@page import="wt.method.jmx.MethodServer"%>
<%@page import="wt.util.WTContext"%>
<%@page import="wt.util.WTProperties"%>
<%@page import="wt.util.jmx.WDSJMXConnector"%>
<%@page import="wt.util.jmx.AccessUtil"%>
<%@page import="wt.util.jmx.JmxConnectUtil"%>
<%@page import="wt.util.jmx.serverStatusResource"%>
<%@page import="javax.servlet.jsp.JspWriter"%>

<%-- Set up various constants for re-use between requests--%>
<%!
 
 private static final String  WHC_PREFIX = "Whc";
 private static final String  SOLR_PREFIX = "Solr";

 private static final String  windchillWebAppPath;
 private static final String  whcWebAppPath;
 private static final String  solrWebAppPath;
 private static final String  helpUrl;
 private static final boolean  restrictToSiteAdministrators;
 static
 {
   final Properties  wtProps = MBeanUtilities.getProperties();
   windchillWebAppPath = "/" + wtProps.getProperty( "wt.webapp.name" );
   whcWebAppPath = windchillWebAppPath + "-WHC";
   solrWebAppPath = "/" + wtProps.getProperty( "wt.solr.webapp.name" );
   helpUrl = wt.help.HelpLinkHelper.createHelpHREF( "ServerStatusAbout" );
   restrictToSiteAdministrators = "true".equals( wtProps.getProperty( "wt.serverStatus.restrictToSiteAdministrators" ) );
 }

 private static final String  thisJvmName = ManagementFactory.getRuntimeMXBean().getName();
 private static final String  thisMethodServerName = MethodServer.getStaticDisplayName();

 private static final ObjectName  dumperMBeanName = newObjectName( "com.ptc:wt.subsystem=Dumper" );
 private static final ObjectName  runtimeMBeanName = newObjectName( ManagementFactory.RUNTIME_MXBEAN_NAME );
 private static final ObjectName  gcMonitorMBeanName = newObjectName( "com.ptc:wt.subsystem=Monitors,wt.monitorType=GarbageCollection" );
 private static final ObjectName  memMonitorMBeanName = newObjectName( "com.ptc:wt.subsystem=Monitors,wt.monitorType=Memory" );
 private static final ObjectName  cpuMonitorMBeanName = newObjectName( "com.ptc:wt.subsystem=Monitors,wt.monitorType=ProcessCpuTime" );
 private static final ObjectName  osMBeanName = newObjectName( ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME );
 private static final ObjectName  methodServerMProxyMBeanName = newObjectName( "com.ptc:wt.processGroup=MethodServers" );
 private static final ObjectName  methodServerMBeanName = newObjectName( "com.ptc:wt.type=MethodServer" );
 private static final ObjectName  methodContextsMBeanName = newObjectName( "com.ptc:wt.subsystem=Monitors,wt.monitorType=MethodContexts" );
 private static final ObjectName  seRequestMonitorMBeanName = newObjectName( "com.ptc:wt.servlet.system=WebAppContexts,wt.webAppContext=" + windchillWebAppPath +
                                                                             ",wt.subsystem=Monitors,wt.servlet.subsystem=ServletRequests" );
 private static final ObjectName  sessionMonitorMBeanName = newObjectName( "com.ptc:wt.servlet.system=WebAppContexts,wt.webAppContext=" + windchillWebAppPath +
                                                                           ",wt.subsystem=Monitors,wt.servlet.subsystem=ServletSessions" );
 private static final ObjectName  whcRequestMonitorMBeanName = newObjectName( "com.ptc:wt.servlet.system=WebAppContexts,wt.webAppContext=" + whcWebAppPath +
                                                                              ",wt.subsystem=Monitors,wt.servlet.subsystem=ServletRequests" );
 private static final ObjectName  solrRequestMonitorMBeanName = newObjectName( "com.ptc:wt.servlet.system=WebAppContexts,wt.webAppContext=" + solrWebAppPath +
                                                                               ",wt.subsystem=Monitors,wt.servlet.subsystem=ServletRequests" );
 private static final ObjectName  activeUsersMBeanName = newObjectName( "com.ptc:wt.subsystem=Monitors,Name=ActiveUsers" );
 private static final ObjectName  serverManagerMBeanName = newObjectName( "com.ptc:wt.type=ServerManager" );
 private static final ObjectName  vaultSitesMBeanName = newObjectName( "com.ptc:wt.subsystem=Monitors,wt.monitorType=VaultSites" );

 private static final String  dumperMBeanAttrs[] = new String[] { "DeadlockedThreadIds" };
 private static final String  runtimeMBeanAttrs[] = new String[] { "StartTime", "Uptime" };
 private static final String  msRuntimeMBeanAttrs[] = new String[] { "StartTime", "Name", "Uptime" };
 private static final String  dsRuntimeMBeanAttrs[] = new String[] { "Name", "Uptime" };
 private static final String  gcMonitorMBeanAttrs[] = new String[] { "PercentTimeSpentInGCThreshold", "RecentPercentTimeSpentInGC", "OverallPercentTimeSpentInGC" };
 private static final String  memMonitorMBeanAttrs[] = new String[] { "HeapPercentUsageThreshold", "HeapPercentUsage", "PermGenPercentUsageThreshold", "PermGenPercentUsage" };
 private static final String  cpuMonitorMBeanAttrs[] = new String[] { "ProcessPercentCpuThreshold", "RecentCpuData", "AverageProcessPercentCpu" };
 private static final String  osMBeanAttrs[] = new String[] { "FreePhysicalMemorySize", "TotalPhysicalMemorySize", "FreeSwapSpaceSize", "TotalSwapSpaceSize", "SystemLoadAverage" };
 private static final String  methodServerMBeanAttrs[] = new String[] { "JmxServiceURL" };
 private static final String  methodContextsMBeanAttrs[] = new String[] { "MaxAverageActiveContextsThreshold", "RecentStatistics", "BaselineStatistics" };
 private static final String  seRequestMonitorMBeanAttrs[] = new String[] { "MaxAverageActiveRequestsThreshold", "RequestTimeWarnThreshold", "RecentStatistics", "BaselineStatistics" };
 private static final String  sessionMonitorMBeanAttrs[] = new String[] { "MaxAverageActiveSessionsThreshold", "ActiveSessions", "BaselineStatistics" };
 private static final String  serverManagerMBeanAttrs[] = new String[] { "CacheMaster", "JmxServiceURL" };

 private static final Object  windchillDsGetAttrsArgs[] =
 {
   new ObjectName[] {
     runtimeMBeanName,
     gcMonitorMBeanName,
     memMonitorMBeanName,
     cpuMonitorMBeanName,
     dumperMBeanName,
     osMBeanName
   },
   null,
   new String[][] {
     dsRuntimeMBeanAttrs,
     gcMonitorMBeanAttrs,
     memMonitorMBeanAttrs,
     cpuMonitorMBeanAttrs,
     dumperMBeanAttrs,
     osMBeanAttrs
   }
 };
 private static final Object  serverManagerGetAttrsArgs[] =
 {
   new ObjectName[] {
     runtimeMBeanName,
     gcMonitorMBeanName,
     memMonitorMBeanName,
     cpuMonitorMBeanName,
     dumperMBeanName,
     osMBeanName,
     serverManagerMBeanName
   },
   null,
   new String[][] {
     runtimeMBeanAttrs,
     gcMonitorMBeanAttrs,
     memMonitorMBeanAttrs,
     cpuMonitorMBeanAttrs,
     dumperMBeanAttrs,
     osMBeanAttrs,
     serverManagerMBeanAttrs
   }
 };
 private static final Object  methodServersGetAttrsArgs[] =
 {
   new ObjectName[] {
     runtimeMBeanName,
     gcMonitorMBeanName,
     memMonitorMBeanName,
     cpuMonitorMBeanName,
     dumperMBeanName,
     methodServerMBeanName,
     methodContextsMBeanName,
     sessionMonitorMBeanName,
     seRequestMonitorMBeanName,
     whcRequestMonitorMBeanName,
     solrRequestMonitorMBeanName
   },
   null,
   new String[][] {
     msRuntimeMBeanAttrs,
     gcMonitorMBeanAttrs,
     memMonitorMBeanAttrs,
     cpuMonitorMBeanAttrs,
     dumperMBeanAttrs,
     methodServerMBeanAttrs,
     methodContextsMBeanAttrs,
     sessionMonitorMBeanAttrs,
     seRequestMonitorMBeanAttrs,
     seRequestMonitorMBeanAttrs,
     seRequestMonitorMBeanAttrs
   }
 };
 private static final ObjectName  thisMethodServerGetAttrsBeans[] =
 {
   runtimeMBeanName,
   gcMonitorMBeanName,
   memMonitorMBeanName,
   cpuMonitorMBeanName,
   dumperMBeanName,
   methodServerMBeanName,
   methodContextsMBeanName,
   sessionMonitorMBeanName,
   seRequestMonitorMBeanName,
   whcRequestMonitorMBeanName,
   solrRequestMonitorMBeanName,
   osMBeanName
 };
 private static final String  thisMethodServerGetAttrsAttrs[][] =
 {
   runtimeMBeanAttrs,
   gcMonitorMBeanAttrs,
   memMonitorMBeanAttrs,
   cpuMonitorMBeanAttrs,
   dumperMBeanAttrs,
   methodServerMBeanAttrs,
   methodContextsMBeanAttrs,
   sessionMonitorMBeanAttrs,
   seRequestMonitorMBeanAttrs,
   seRequestMonitorMBeanAttrs,
   seRequestMonitorMBeanAttrs,
   osMBeanAttrs
 };

 private static final String  getAttributesSignature[] = { ObjectName[].class.getName(), QueryExp[].class.getName(), String[][].class.getName() };

 private static final String  rbClassname = serverStatusResource.class.getName();
%>
<%
 final boolean  isPrivilegedUser = AccessUtil.isSiteAdministrator();
 if ( restrictToSiteAdministrators )
   if ( !isPrivilegedUser )
     throw new AccessControlException("Not a site administrator!");
 
 //Gather all data
 // get JVM name of default server manager
 final String  defaultSmJvmName = getDefaultServerManagerJvmName();

 // get time right before we start result collection
 final long  dataCollectionStart = System.currentTimeMillis();

 // collect data for WindchillDS
 Map<ObjectName,AttributeList>  windchillDSResults[] = null;
 Object  dsJmxUrlString = null;
 Throwable  wcDsResultRetrievalException = null;
 try
 {
   final JMXConnector  wcDsJmxConnection = WDSJMXConnector.getWDSJMXConnector();
   dsJmxUrlString = WDSJMXConnector.getWDSJMXServiceURL();
   try
   {
     final MBeanServerConnection  mbeanServer = wcDsJmxConnection.getMBeanServerConnection();
     windchillDSResults = (Map<ObjectName,AttributeList>[]) mbeanServer.invoke(
                             dumperMBeanName, "getAttributes", windchillDsGetAttrsArgs, getAttributesSignature );
   }
   finally
   {
     wcDsJmxConnection.close();
   }
 }
 catch ( VirtualMachineError e )
 {
   throw e;
 }
 catch ( Throwable t )
 {
   wcDsResultRetrievalException = t;  // remember but otherwise eat exception
 }

 // fetch VaultSite status information
 final CompositeData  vaultSiteStatusInfo = getVaultSiteStatusInfo();

 // collect data on method servers and server managers
 Integer  activeUsers = null;
 Map<String,Object>  methodServerResults = null;
 Map<String,Object>  serverManagerResults = null;
 Throwable  resultRetrievalException = null;
 try
 {
   // establish JMX connection to default server manager to collect JMX data from server managers and method servers
   final JMXConnector  smConnection = JmxConnectUtil.getDefaultServerManagerLocalConnector();
   try
   {
     final MBeanServerConnection  mbeanServer = smConnection.getMBeanServerConnection();

     // produce dynamic proxy for the "MethodServers" MBean in default server manager
     final MethodServerMProxyMBean  methodServersMBeanProxy =
             MBeanServerInvocationHandler.newProxyInstance( mbeanServer, methodServerMProxyMBeanName,
                                                            MethodServerMProxyMBean.class, false );

     // grab data from all method servers (yes, this is a bit ugly, but it is all done in one request -- no chatter)
     methodServerResults = methodServersMBeanProxy.invokeInfoOpInAllClusterMethodServers(
                             dumperMBeanName, "getAttributes", methodServersGetAttrsArgs, getAttributesSignature );

     // fetch active user count (done separately as we only need the result from one server manager, not all)
     try
     {
       activeUsers = (Integer) mbeanServer.getAttribute( activeUsersMBeanName, "TotalActiveUserCount" );
     }
     catch ( InstanceNotFoundException e )
     {
       activeUsers = 0;  // must not have been any active users yet and thus this MBean has not yet been registered
     }

     // grab data from all server managers (yes, this is a bit ugly, but it is all done in one request -- no chatter)
     serverManagerResults = methodServersMBeanProxy.invokeInfoOpInAllServerManagers(
                             dumperMBeanName, "getAttributes", serverManagerGetAttrsArgs, getAttributesSignature );
   }
   finally
   {
     smConnection.close();
   }
 }
 catch ( VirtualMachineError e )
 {
   throw e;
 }
 catch ( Throwable t )
 {
   resultRetrievalException = t;  // remember but otherwise eat exception
 }

 // we're done collecting data now (usually, but not quite always, hence the lack of 'final' here)
 long  dataCollectionEnd = System.currentTimeMillis();

 // collate server manager, method server, and servlet engine results into somewhat easier to use format
 final Map<String,Map<String,Object>>  smToAttrMap = new TreeMap<String,Map<String,Object>>();
 final Map<String,Throwable>  smToExceptionMap = new TreeMap<String,Throwable>();
 final Map<String,Map<String,Map<String,Object>>>  smToMsToAttrMap = new HashMap<String,Map<String,Map<String,Object>>>();
 final Map<String,Map<String,Throwable>>  smToMsToExceptionMap = new HashMap<String,Map<String,Throwable>>();
 if ( serverManagerResults != null )
   for ( Map.Entry<String,Object> serverManagerResultEntry : serverManagerResults.entrySet() )
   {
     final String  serverManagerName = serverManagerResultEntry.getKey();
     final Map<String,Map<String,Object>>  msToAttrMap = new TreeMap<String,Map<String,Object>>();
     smToMsToAttrMap.put( serverManagerName, msToAttrMap );
     final Map<String,Throwable>  msToExceptionMap = new TreeMap<String,Throwable>();
     smToMsToExceptionMap.put( serverManagerName, msToExceptionMap );
     final Object  smResult = serverManagerResultEntry.getValue();
     if ( smResult instanceof Map[] )
     {
       smToAttrMap.put( serverManagerName, collate( (Map<ObjectName,AttributeList>[]) smResult ) );
       collateResultsFromServerManager( serverManagerName, methodServerResults, msToAttrMap, msToExceptionMap );
     }
     else if ( smResult instanceof Throwable )
       smToExceptionMap.put( serverManagerName, (Throwable) smResult );
   }

 // grab all data of interest from this method server *if* it's not already covered by the data we have so far (which it should be)
 Map<String,Object>  thisMsAttrMap = null;
 Exception  localMsException = null;
 if ( !containsResultsForMs( smToMsToAttrMap, thisMethodServerName ) )
 {
   try
   {
     // could obtain this via a variety of direct API calls (and used to), but this is more consistent with the rest of the code here
     final Dumper  dumper = Dumper.getInstance( null, true );
     final Map<ObjectName,AttributeList>  msResults[] = dumper.getAttributes( thisMethodServerGetAttrsBeans, null,
                                                                              thisMethodServerGetAttrsAttrs );
     dataCollectionEnd = System.currentTimeMillis();  // reset end of data collection, since we just collected more data
     thisMsAttrMap = collate( msResults );
   }
   catch ( Exception e )
   {
     localMsException = e;
   }
 }

 // collate Windchill DS results into handy map
 final Map<String,Object>  wcDsAttrMap = ( ( windchillDSResults != null ) ? collate( windchillDSResults ) : null );

 // get siteStatusData
 final TabularData  siteStatusData = ( ( vaultSiteStatusInfo != null ) ? (TabularData) vaultSiteStatusInfo.get( "siteStatusData" ) : null );

 // All data of interest is now gathered, so now we just have to present it
 
 // determine resource bundle, decimal and date format, and localized percent symbol for use throughout and set up various other data for re-use
 Locale localeObj = new Locale("en", "US"); 
 final DecimalFormatSymbols  decimalSymbols = new DecimalFormatSymbols( localeObj );
 final DecimalFormat  decimalFormat = new DecimalFormat( "0.###", decimalSymbols );
 final String  percentString = xmlEscape( decimalSymbols.getPercent() );  // pre-escaped localized % symbol
 final SimpleDateFormat  dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS Z" );
 dateFormat.setTimeZone( WTContext.getContext().getTimeZone() );
 final String  webAppContextPaths[] = { windchillWebAppPath, whcWebAppPath, solrWebAppPath };
 final String  webAppPrefixes[] = { "", WHC_PREFIX, SOLR_PREFIX };
 final String  webAppLabelKeys[] = { serverStatusResource.GENERAL_SERVLET_REQUESTS_LABEL,
                                     serverStatusResource.HELP_SERVLET_REQUESTS_LABEL,
                                     serverStatusResource.SOLR_SERVLET_REQUESTS_LABEL };
 final String  percContextTimeAttrNames[] =
 {
   "percentageOfContextTimeInJDBCCalls",
   "percentageOfContextTimeInJDBCConnWait",
   "percentageOfContextTimeInJNDICalls"
 };
 /*
 final String  percContextTimeLabels[] =
 {
   RB.getString( serverStatusResource.IN_JDBC_CALLS ),
   RB.getString( serverStatusResource.IN_JDBC_CONN_WAIT ),
   RB.getString( serverStatusResource.IN_JNDI_CALLS )
 };
 */
 final String  percContextTimeChartJsps[] =
 {
   "percTimeInJdbcChart.jsp",
   "percTimeInJdbcWaitChart.jsp",
   "percTimeInJndiChart.jsp"
 };

 // by zhaoxp start
 /*
 out.println("Active User Number: "+activeUsers+"<br>");
 out.println("------------------------------<br>");
 out.println("defaultSmJvmName = "+defaultSmJvmName+"<br>");
 out.println("------------------------------<br>");
 */
 /*
 //out.println("out.getClass().getName() = "+out.getClass().getName()); //org.apache.jasper.runtime.JspWriterImpl
 JspWriter out1 = pageContext.getOut();
 out.println("out==out1?"+(out==out1));
 */
 try{
     //response.setHeader("Content-Type","video/x-msvideo");
     //response.setContentType("text/json; charset=utf-8");
     response.setContentType("application/json");
     response.setCharacterEncoding("UTF-8");
     //response.setContentType("text/javascript; charset=utf-8");
     //response.setContentType("text/plain; charset=utf-8");
     
     PrintWriter printWriter = response.getWriter();
     Map<String,Object> statusMap=new HashMap<String,Object>();
     statusMap.put("version","20161101");
     statusMap.put("xauthor","zhaoxp");
     
     statusMap.put("ActiveUsers",activeUsers);
     statusMap.put("defaultSmJvmName",defaultSmJvmName);
     statusMap.put("thisMethodServerName",thisMethodServerName);
     statusMap.put("WindchillDSInfo",getWindchillDSInfo(wcDsAttrMap));
     statusMap.put("ServerManagerInfo",getSMAndMSInfo(smToAttrMap,smToMsToAttrMap));
     statusMap.put("SMToException",getSMToExceptionMap(smToExceptionMap));
     statusMap.put("SMToMSToException",getSMToMSToExceptionMap(smToMsToExceptionMap));
     
     StringBuffer strBuf=new StringBuffer();
     getJsonString(statusMap,strBuf);
     printWriter.print(strBuf);
     //printWriter.print("\n\n");
     
     //printWriter.print(encode_json(statusMap));
     
     //printJsonFormat(statusMap,1,"","",printWriter);
     //printJsonFormat(statusMap,1,"&nbsp;&nbsp;","<br>",printWriter);
     
     printWriter.flush();
     printWriter.close();
     /*
     out.println("<br><br>Refrecne:<br>");
     //--WindchillDS info
     out.println("print windchillDSResults info <br>");
     printInfo(wcDsAttrMap,out);
     out.println("<br>");
     //--current methodserver name
     out.println("thisMethodServerName = "+thisMethodServerName+"<br>");
     out.println("<br>");

     //--servermanager info
     out.println("print ServerManager Info <br>");
     printSMToAttrMap(smToAttrMap,out);
     out.println("<br>");

     //--methodserver info
     printSMToMSToAttrMap(smToMsToAttrMap,out);
     
     //--exception: 1 smToExceptionMap; 2 smToMsToExceptionMap
     out.println("<br>");
     printSMToException(smToExceptionMap,out);
     out.println("<br>");
     printSMToMSToException(smToMsToExceptionMap,out);
     */
     
 }catch(Exception e){
     out.println("Exception : "+e+"<br>");
     e.printStackTrace();
 }
 // by zhaoxp  end 
%>

<%!
 
 private static Map<String,Object> getSMAndMSInfo(Map<String,Map<String,Object>> smToAttrMap,Map<String,Map<String,Map<String,Object>>> smToMsToAttrMap){
     Map<String,Object> map=new HashMap<String,Object>();
     map.put("ServerManagerCount",smToAttrMap.size());
     for(Map.Entry<String,Map<String,Object>> entry:smToAttrMap.entrySet()){
         String servermanagerName=entry.getKey();
         Map<String,Object> smMap=entry.getValue();
         map.put(servermanagerName,getSMInfo(servermanagerName,smMap,smToMsToAttrMap));
         if(map.containsKey("ServerManagerNames")){
             String smNames = (String)map.get("ServerManagerNames");
             smNames+=","+servermanagerName;
             map.put("ServerManagerNames",smNames);
         }else{
             map.put("ServerManagerNames",servermanagerName);
         }
     }
     return map;
 }
 
 private static Map<String,Object> getSMInfo(String servermanagerName,Map<String,Object> smMap,Map<String,Map<String,Map<String,Object>>> smToMsToAttrMap){
     Map<String,Object> map=new HashMap<String,Object>();
     map.put("Uptime",smMap.get("Uptime"));
     map.put("HeapPercentUsage",smMap.get("HeapPercentUsage"));
     map.put("PermGenPercentUsage",smMap.get("PermGenPercentUsage"));
     map.put("OverallPercentTimeSpentInGC",smMap.get("OverallPercentTimeSpentInGC"));
     map.put("RecentPercentTimeSpentInGC",smMap.get("RecentPercentTimeSpentInGC"));
     map.put("AverageProcessPercentCpu",smMap.get("AverageProcessPercentCpu"));
     map.put("SystemLoadAverage",smMap.get("SystemLoadAverage"));
     map.put("CacheMaster",smMap.get("CacheMaster"));
     map.put("StartTime",smMap.get("StartTime"));
     map.put("TotalPhysicalMemorySize",smMap.get("TotalPhysicalMemorySize"));
     map.put("FreePhysicalMemorySize",smMap.get("FreePhysicalMemorySize"));
     map.put("TotalSwapSpaceSize",smMap.get("TotalSwapSpaceSize"));
     map.put("FreeSwapSpaceSize",smMap.get("FreeSwapSpaceSize"));
     /*
     map.put("",smMap.get(""));
     */
     CompositeDataSupport cds=(CompositeDataSupport)smMap.get("RecentCpuData");
     map.put("RecentProcessPercentCpu",cds.get("processPercentCpu"));
     
     Map<String,Map<String,Object>> map2=smToMsToAttrMap.get(servermanagerName);
     for(Map.Entry<String,Map<String,Object>> entry:map2.entrySet()){
         String methodserverName=entry.getKey();
         Map msMap=entry.getValue();
         if(map.containsKey("MethodServerNames")){
             String msNames=(String)map.get("MethodServerNames");
             msNames+=","+methodserverName;
             map.put("MethodServerNames",msNames);
         }else{
             map.put("MethodServerNames",methodserverName);
         }
         map.put(methodserverName,getMSInfo(methodserverName,msMap));
     }
     return map;
 }
 
 private static Map<String,Object> getMSInfo(String methodserverName,Map<String,Object> msMap){
     Map<String,Object> map=new HashMap<String,Object>();
     map.put("Name",msMap.get("Name"));
     map.put("StartTime",msMap.get("StartTime"));
     map.put("Uptime",msMap.get("Uptime"));
     map.put("OverallPercentTimeSpentInGC",msMap.get("OverallPercentTimeSpentInGC"));
     map.put("RecentPercentTimeSpentInGC",msMap.get("RecentPercentTimeSpentInGC"));
     map.put("HeapPercentUsage",msMap.get("HeapPercentUsage"));
     map.put("PermGenPercentUsage",msMap.get("PermGenPercentUsage"));
     map.put("AverageProcessPercentCpu",msMap.get("AverageProcessPercentCpu"));
     map.put("ActiveSessions",msMap.get("ActiveSessions"));
     map.put("DeadlockedThreadIds",msMap.get("DeadlockedThreadIds"));
     
     CompositeDataSupport cdsRecentCPU=(CompositeDataSupport)msMap.get("RecentCpuData");
     CompositeDataSupport cdsRecentStat=(CompositeDataSupport)msMap.get("RecentStatistics");
     CompositeDataSupport cdsBaseStat=(CompositeDataSupport)msMap.get("BaselineStatistics");
     
     CompositeDataSupport cdsSesssionBaseStat=(CompositeDataSupport)msMap.get("SessionBaselineStatistics");
     CompositeDataSupport cdsRequestRecentStat=(CompositeDataSupport)msMap.get("RequestRecentStatistics");
     CompositeDataSupport cdsRequestBaseStat=(CompositeDataSupport)msMap.get("RequestBaselineStatistics");
     CompositeDataSupport cdsWhcRequestBaseStat=(CompositeDataSupport)msMap.get("WhcRequestBaselineStatistics");
     CompositeDataSupport cdsWhcRequestRecentStat=(CompositeDataSupport)msMap.get("WhcRequestRecentStatistics");
     //CPU used by process
     map.put("RecentProcessPercentCpu",cdsRecentCPU.get("processPercentCpu"));
     //servlet request(recent:RequestRecentStatistics | baseline:RequestBaselineStatistics) 
     //1 active session; 2 completed requests; 3 average response time; 4 max concurrency; 5 average concurrency
     if(cdsSesssionBaseStat!=null){
         map.put("SessionBaselineStatistics.activeSessionsAverage",cdsSesssionBaseStat.get("activeSessionsAverage"));
     }
     if(cdsRequestRecentStat!=null&&cdsRequestBaseStat!=null){
         map.put("RequestRecentStatistics.completedRequests",cdsRequestRecentStat.get("completedRequests"));
         map.put("RequestBaselineStatistics.completedRequests",cdsRequestBaseStat.get("completedRequests"));
         
         map.put("RequestRecentStatistics.requestSecondsAverage",cdsRequestRecentStat.get("requestSecondsAverage"));
         map.put("RequestBaselineStatistics.requestSecondsAverage",cdsRequestBaseStat.get("requestSecondsAverage"));
         
         //for test
         //Object tmpObj=cdsWhcRequestBaseStat.get("requestSecondsAverage");
         //System.out.println("================================="+tmpObj.getClass().getName());
         //map.put("Test_WhcRequestBaselineStatistics.requestSecondsAverage",tmpObj);
         //for test

         map.put("RequestRecentStatistics.activeRequestsMax",cdsRequestRecentStat.get("activeRequestsMax"));
         map.put("RequestBaselineStatistics.activeRequestsMax",cdsRequestBaseStat.get("activeRequestsMax"));

         map.put("RequestRecentStatistics.activeRequestsAverage",cdsRequestRecentStat.get("activeRequestsAverage"));
         map.put("RequestBaselineStatistics.activeRequestsAverage",cdsRequestBaseStat.get("activeRequestsAverage"));
     }
     //methd context (recnet:cdsRecentStat | baseline:cdsBaseStat )
     // 1 Completed Contexts; 2 Maximum Concurrency; 3 Average Concurrency
     map.put("RecentStatistics.completedContexts",cdsRecentStat.get("completedContexts"));
     map.put("BaselineStatistics.completedContexts",cdsBaseStat.get("completedContexts"));
     
     map.put("RecentStatistics.activeContextsMax",cdsRecentStat.get("activeContextsMax"));
     map.put("BaselineStatistics.activeContextsMax",cdsBaseStat.get("activeContextsMax"));
     
     map.put("RecentStatistics.activeRequestsMax",cdsRecentStat.get("activeContextsAverage"));
     map.put("BaselineStatistics.activeRequestsMax",cdsBaseStat.get("activeContextsAverage"));
     //method context time (recnet:cdsRecentStat | baseline:cdsBaseStat )
     // 1 In JDBC Calls; 2 In JDBC Connection Wait; 3 In JNDI Calls
     map.put("RecentStatistics.percentageOfContextTimeInJDBCCalls",cdsRecentStat.get("percentageOfContextTimeInJDBCCalls"));
     map.put("BaselineStatistics.percentageOfContextTimeInJDBCCalls",cdsBaseStat.get("percentageOfContextTimeInJDBCCalls"));
     
     map.put("RecentStatistics.percentageOfContextTimeInJDBCConnWait",cdsRecentStat.get("percentageOfContextTimeInJDBCConnWait"));
     map.put("BaselineStatistics.percentageOfContextTimeInJDBCConnWait",cdsBaseStat.get("percentageOfContextTimeInJDBCConnWait"));
     
     map.put("RecentStatistics.percentageOfContextTimeInJNDICalls",cdsRecentStat.get("percentageOfContextTimeInJNDICalls"));
     map.put("BaselineStatistics.percentageOfContextTimeInJNDICalls",cdsBaseStat.get("percentageOfContextTimeInJNDICalls"));
     /*
     map.put("",msMap.get(""));
     */
     return map;
 }

 private static Map<String,Object> getWindchillDSInfo(Map<String,Object>  wcDsAttrMap){
     CompositeDataSupport cds;
     Map<String,Object> dsInfoMap=new HashMap<String,Object>();
     dsInfoMap.put("Name",wcDsAttrMap.get("Name"));
     dsInfoMap.put("Uptime",wcDsAttrMap.get("Uptime"));
     dsInfoMap.put("HeapPercentUsage",wcDsAttrMap.get("HeapPercentUsage"));
     dsInfoMap.put("PermGenPercentUsage",wcDsAttrMap.get("PermGenPercentUsage"));
     dsInfoMap.put("SystemLoadAverage",wcDsAttrMap.get("SystemLoadAverage"));
     dsInfoMap.put("DeadlockedThreadIds",wcDsAttrMap.get("DeadlockedThreadIds"));
     dsInfoMap.put("OverallPercentTimeSpentInGC",wcDsAttrMap.get("OverallPercentTimeSpentInGC"));
     dsInfoMap.put("AverageProcessPercentCpu",wcDsAttrMap.get("AverageProcessPercentCpu"));
     dsInfoMap.put("RecentPercentTimeSpentInGC",wcDsAttrMap.get("RecentPercentTimeSpentInGC"));

     cds=(CompositeDataSupport)wcDsAttrMap.get("RecentCpuData");
     dsInfoMap.put("RecentProcessPercentCpu",cds.get("processPercentCpu"));
     return dsInfoMap;
 }
 
 private static String encode_json(Map<String,Object> mapData){
     StringBuffer strBuf=new StringBuffer();
     strBuf.append("{");
     boolean start=true;
     for(Map.Entry<String,Object> entry:mapData.entrySet()){
         if(!start){
             strBuf.append(",");
         }else{
             start=false;
         }
         strBuf.append("\""+entry.getKey()+"\":");
         Object val=entry.getValue();
         if(val instanceof Map){
             strBuf.append(encode_json((Map)val));
         }else if(val instanceof Number){
             java.text.NumberFormat formatter=java.text.NumberFormat.getInstance();
             formatter.setGroupingUsed(false);
             strBuf.append(formatter.format(val));
         }else if(val instanceof String){
             strBuf.append("\""+val+"\"");
         }else{
             strBuf.append(val);
         }
     }
     strBuf.append("}");
     return strBuf.toString();
 }
 
 private static void getJsonString(Map<String,Object> mapData,StringBuffer strBuf){
     int mapSize=mapData.size();
     int index=0;
     strBuf.append("{");
     java.text.NumberFormat formatter=java.text.NumberFormat.getInstance();
     formatter.setGroupingUsed(false);
     for(Map.Entry<String,Object> entry:mapData.entrySet()){
         String key=entry.getKey();
         Object val=entry.getValue();
         strBuf.append("\""+key+"\":");
         if(val instanceof Map){
             getJsonString((Map)val,strBuf);
         }else if(val instanceof Number){
             if((val instanceof Float)&&((Float)val).isNaN()){
                 strBuf.append("0");
             }else if((val instanceof Double)&&(((Double)val).isNaN())){
                 strBuf.append("0");
             }else{
                strBuf.append(formatter.format(val));
             }
         }else if(val instanceof String){
             strBuf.append("\""+val+"\"");
         }else{
             strBuf.append(val);
         }
         index+=1;
         if(index!=mapSize){
             strBuf.append(",");
         }
     }
     strBuf.append("}");
 }

 private static void printJsonFormat(Map<String,Object> mapData,int indentNumber,String indent,String sperator,PrintWriter printWriter)throws IOException{
     String indentStr0="";
     String indentStr="";
     int count=0;
     while(count<(indentNumber-1)){
         indentStr0+=indent;
         count++;
     }
     indentStr=indentStr0+indent;
     printWriter.print(indentStr0+"{"+sperator);
     int mapSize=mapData.size();
     int index=0;
     java.text.NumberFormat formatter=java.text.NumberFormat.getInstance();
     formatter.setGroupingUsed(false);
     for(Map.Entry<String,Object> entry:mapData.entrySet()){
         String key=entry.getKey();
         Object val=entry.getValue();
         printWriter.print(indentStr+"\""+key+"\":");
         if(val instanceof Map){
             printWriter.print(sperator);
             printJsonFormat((Map)val,indentNumber+1,indent,sperator,printWriter);
          }else if(val instanceof Number){
              if((val instanceof Float)&&((Float)val).isNaN()){
                  printWriter.print("0");
              }else if((val instanceof Double)&&(((Double)val).isNaN())){
                  printWriter.print("0");
              }else{
                printWriter.print(formatter.format(val));
             }
          }else if(val instanceof String){
              printWriter.print("\""+val+"\"");
          }else{
              printWriter.print(val);
          }
         index+=1;
         if(index!=mapSize){
             printWriter.print(",");
         }
         printWriter.print(sperator);
     }
     printWriter.print(indentStr0+"}");
 }
 
 private static Map<String,String> getSMToExceptionMap(Map<String,Throwable>  smToExceptionMap){
     Map<String,String> map=new HashMap<String,String>();
     for(Map.Entry<String,Throwable> entry:smToExceptionMap.entrySet()){
         String smExName=entry.getKey();
         Throwable th=entry.getValue();
         map.put(smExName,th.toString());
     }
     return map;
 }
 
 private static void printSMToException(Map<String,Throwable>  smToExceptionMap,JspWriter out) throws IOException{
     out.println("printSMToException ...<br>");
     out.println("<table border='1'><tr><td>Exception Name</td><td>Throwable</td></tr>");
     for(Map.Entry<String,Throwable> entry:smToExceptionMap.entrySet()){
         String smExName=entry.getKey();
         Throwable th=entry.getValue();
         out.println("<tr><td>"+smExName+"</td><td>"+th+"</td></tr>");
     }
     out.println("</table>");
 }
 
 private static Map<String,Map<String,String>> getSMToMSToExceptionMap(Map<String,Map<String,Throwable>>  smToMsToExceptionMap){
     Map<String,Map<String,String>> map=new HashMap<String,Map<String,String>>();
     for(Map.Entry<String,Map<String,Throwable>> entry:smToMsToExceptionMap.entrySet()){
         String smName=entry.getKey();
         Map<String,Throwable> valMap=entry.getValue();
         Map<String,String> tmp=new HashMap<String,String>();
         for(Map.Entry<String,Throwable> entry2:valMap.entrySet()){
             String exName=entry2.getKey();
             Throwable th=entry2.getValue();
             tmp.put(exName,th.toString());
         }
         map.put(smName,tmp);
     }
     return map;
 }
 
 private static void printSMToMSToException(Map<String,Map<String,Throwable>>  smToMsToExceptionMap,JspWriter out) throws IOException{
     out.println("printSMToMSToException ...<br>");
     out.println("<table border='1'><tr><td>SM Name</td><td>Exception Name</td><td>Throwable</td></tr>");
     out.println("");
     for(Map.Entry<String,Map<String,Throwable>> entry:smToMsToExceptionMap.entrySet()){
         String smName=entry.getKey();
         Map<String,Throwable> map=entry.getValue();
         for(Map.Entry<String,Throwable> entry2:map.entrySet()){
             String exName=entry2.getKey();
             Throwable th=entry2.getValue();
             out.println("<tr><td>"+smName+"</td><td>"+exName+"</td><td>"+th+"</td></tr>");
         }
     }
     out.println("</table>");
 }
 /*
 private static void getWCDSInfo(Map<ObjectName,AttributeList>  windchillDSResults)throws IOException{
     for(Map<ObjectName,AttributeList> map:windchillDSResults){
         Iterator<ObjectName> it=map.keySet().iterator();
     }
 }*/
 
 private static void printSMToAttrMap(Map<String,Map<String,Object>> smToAttrMap,JspWriter out) throws IOException{
     out.println("<table border='1'><tr><td>ServerManager Name</td><td>Key</td><td>Value</td><td>Class</td></tr>");
     for(Map.Entry<String,Map<String,Object>> entry:smToAttrMap.entrySet()){
         String servermanagerName=entry.getKey();
         Map<String,Object> map=entry.getValue();
         for(Map.Entry<String,Object> entry2:map.entrySet()){
             String key=entry2.getKey();
             Object val=entry2.getValue();
             if(val!=null){
                 if(val.getClass().getName().equals("javax.management.openmbean.CompositeDataSupport")){
                     
                     CompositeDataSupport cds=(CompositeDataSupport)val;
                     CompositeType ct=cds.getCompositeType();
                     Iterator<String> it=ct.keySet().iterator();
                     String ss="";
                     while(it.hasNext()){
                         String name=it.next();
                         Object val2=cds.get(name);
                         if(val2 instanceof javax.management.openmbean.TabularDataSupport){
                             ss+="<br>---"+name+" = javax.management.openmbean.TabularDataSupport(...)";
                         }else{
                             ss+="<br>---"+name+" = "+cds.get(name);
                         }
                         
                     }
                     out.println("<tr><td>"+servermanagerName+"</td><td>"+key+"</td><td>CompositeDataSupport ... "+ss+"</td><td>"+val.getClass()+"</td></tr>");
                     
                     //out.println("<tr><td>"+servermanagerName+"</td><td>"+key+"</td><td>CompositeDataSupport ... </td><td>"+val.getClass()+"</td></tr>");
                 }else{
                     out.println("<tr><td>"+servermanagerName+"</td><td>"+key+"</td><td>"+val+"</td><td>"+val.getClass()+"</td></tr>");
                 }
             }else{
                 out.println("<tr><td>"+servermanagerName+"</td><td>"+key+"</td><td>"+val+"</td><td>NULL</td></tr>");
             }
         }
     }
     out.println("</table>");
     out.println("<br>");
 }
 
 private static void printSMToMSToAttrMap(Map<String,Map<String,Map<String,Object>>> smToMsToAttrMap,JspWriter out) throws IOException{
     out.println("<table border='1'><tr><td>ServerMamager</td><td>MethodServer</td><td>Key</td><td>Value</td><td>Class</td></tr>");
     for(Map.Entry<String,Map<String,Map<String,Object>>> entry:smToMsToAttrMap.entrySet()){
         String servermanagerName=entry.getKey();
         Map<String,Map<String,Object>> smMap=entry.getValue();
         for(Map.Entry<String,Map<String,Object>> smEnt:smMap.entrySet()){
             String methodserverName=smEnt.getKey();
             Map<String,Object> msMap=smEnt.getValue();
             for(Map.Entry<String,Object> msEnt:msMap.entrySet()){
                 String key=msEnt.getKey();
                 Object val=msEnt.getValue();
                 if(val!=null){
                     if(val.getClass().getName().equals("javax.management.openmbean.CompositeDataSupport")){
                         
                         CompositeDataSupport cds=(CompositeDataSupport)val;
                         CompositeType ct=cds.getCompositeType();
                         Iterator<String> it=ct.keySet().iterator();
                         String ss="";
                         while(it.hasNext()){
                            String name=it.next();
                            Object val2=cds.get(name);
                            if(val2 instanceof javax.management.openmbean.TabularDataSupport){
                                ss+="<br>---"+name+" = javax.management.openmbean.TabularDataSupport(...)";
                            }else{
                                ss+="<br>---"+name+" = "+cds.get(name);
                            }
                         }
                         out.println("<tr><td>"+servermanagerName+"</td><td>"+methodserverName+"</td><td>"+key+"</td><td>CompositeDataSupport ... "+ss+"</td><td>"+val.getClass()+"</td></tr>");
                         
                         //out.println("<tr><td>"+servermanagerName+"</td><td>"+methodserverName+"</td><td>"+key+"</td><td>CompositeDataSupport ... </td><td>"+val.getClass()+"</td></tr>");
                     }else{
                         out.println("<tr><td>"+servermanagerName+"</td><td>"+methodserverName+"</td><td>"+key+"</td><td>"+val+"</td><td>"+val.getClass()+"</td></tr>");
                     }
                 }else{
                     out.println("<tr><td>"+servermanagerName+"</td><td>"+methodserverName+"</td><td>"+key+"</td><td>"+val+"</td><td>NULL</td></tr>");
                 }
                 
             }
             
         }
     }
     out.println("</table>");
 }
 private static void printInfo(Map<String,Object>  infoMap,JspWriter out) throws IOException{
     out.println("<table border='1'><tr><td>Key</td><td>Value</td><td>Class</td></tr>");
     for(Map.Entry<String,Object> mbeanAttrMapEntry : infoMap.entrySet()){
         String key=mbeanAttrMapEntry.getKey();
         Object val=mbeanAttrMapEntry.getValue();
         if(val!=null){
             if(val.getClass().getName().equals("javax.management.openmbean.CompositeDataSupport")){
                 /*
                 CompositeDataSupport cds=(CompositeDataSupport)val;
                 CompositeType ct=cds.getCompositeType();
                 Iterator<String> it=ct.keySet().iterator();
                 String ss="";
                 while(it.hasNext()){
                     String name=it.next();
                     ss+="<br>---"+name+" = "+cds.get(name);
                 }
                 out.println("<tr><td>"+key+"</td><td>CompositeDataSupport ... "+ss+"</td><td>"+val.getClass()+"</td></tr>");
                 */
                 out.println("<tr><td>"+key+"</td><td>CompositeDataSupport ... </td><td>"+val.getClass()+"</td></tr>");
             }else{
                 out.println("<tr><td>"+key+"</td><td>"+val+"</td><td>"+val.getClass()+"</td></tr>");
             }
            //out.print("key = "+key+" | value = "+val+" | class "+val.getClass()+"<br>");
            //out.println("<tr><td>"+key+"</td><td>"+val+"</td><td>"+val.getClass()+"</td></tr>");
         }else{
            //out.print("key = "+key+" | value = "+val+"<br>");
            out.println("<tr><td>"+key+"</td><td>"+val+"</td><td>NULL</td></tr>");
         }
         
     }
     out.println("</table>");
 }
 

 private static String  getDefaultServerManagerJvmName()
 {
   try
   {
     final JmxConnectInfo  jmxConnectInfo = (JmxConnectInfo) RemoteServerManager.getDefault().getInfo().jmxConnectInfo;
     return ( jmxConnectInfo.getJvmName() );
   }
   catch ( VirtualMachineError e )
   {
     throw e;
   }
   catch ( Throwable t )
   {
     return ( null );
   }
 }

 private static CompositeData  getVaultSiteStatusInfo()
 {
   try
   {
     // Use SelfAwareMBean.getSelfAwareMBean() and caste as this will be faster than going through MBeanServer
     return ( ((SiteMonitorMBean)SelfAwareMBean.getSelfAwareMBean( vaultSitesMBeanName )).getSiteStatusInfo() );
   }
   catch ( VirtualMachineError e )
   {
     throw e;
   }
   catch ( Throwable t )
   {
     return ( null );
   }
 }

 // collect into a more handy map form
 private static Map<String,Object>  collate( final Map<ObjectName,AttributeList> mbeanAttrMaps[] )
 {
   final Map<String,Object>  collationMap = new HashMap<String,Object>();
   for ( Map<ObjectName,AttributeList> mbeanAttrMap : mbeanAttrMaps )
     for ( Map.Entry<ObjectName,AttributeList> mbeanAttrMapEntry : mbeanAttrMap.entrySet() )
       collate( mbeanAttrMapEntry.getKey(), collationMap, mbeanAttrMapEntry.getValue() );
   return ( collationMap );
 }

 // collect attribute list into a more handy map form, ensuring uniqueness amongst keys
 //   1) places a prefix on attribute names from WHC and Solr web apps
 //   2) places a prefix on BaselineStatistics and RecentStatistics attribute names from ServletSessions' and ServletRequests'
 private static void  collate( final ObjectName objectName, final Map<String,Object> dataMap, final AttributeList attrs )
 {
   final String  webAppContextPath = objectName.getKeyPropertyList().get( MBeanRegistry.WEB_APP_CONTEXT_PROP_KEY );
   if ( webAppContextPath != null )
   {
     final boolean  isSolrWebApp = solrWebAppPath.equals( webAppContextPath );
     final boolean  isWhcWebApp = whcWebAppPath.equals( webAppContextPath );
     final String  webAppPrefix = ( isSolrWebApp ? SOLR_PREFIX : ( isWhcWebApp ? WHC_PREFIX : "" ) );
     final boolean  isSessionAttr = "ServletSessions".equals( objectName.getKeyPropertyList().get( MBeanRegistry.SERVLET_ENGINE_SUBSYSTEM_PROP_KEY ) );
     for ( Object attrObj : attrs )
     {
       final Attribute  attr = (Attribute) attrObj;
       String  attrName = attr.getName();
       if ( "BaselineStatistics".equals( attrName ) || "RecentStatistics".equals( attrName ) )
         attrName = ( isSessionAttr ? "Session" : "Request" ) + attrName;  // currently assume these attributes are either from ServletSessions or ServletRequests mbeans
       dataMap.put( webAppPrefix + attrName, attr.getValue() );
     }
   }
   else
     for ( Object attrObj : attrs )
     {
       final Attribute  attr = (Attribute) attrObj;
       dataMap.put( attr.getName(), attr.getValue() );
     }
 }

 @SuppressWarnings( "unchecked" )
 private static void  collateResultsFromServerManager( final String serverManagerName, final Map<String,Object> resultsForAllSms,
                                                       final Map<String,Map<String,Object>> jvmNameToAttrMap,
                                                       final Map<String,Throwable> jvmNameToExceptionMap )
 {
   if ( resultsForAllSms != null )
   {
     final Object smResultsObj = resultsForAllSms.get( serverManagerName );
     if ( smResultsObj instanceof Map )
     {
       final Map<String,Object>  smResults = (Map<String,Object>) smResultsObj;
       for ( Map.Entry<String,Object> smResultsEntry : smResults.entrySet() )
       {
         final String  jvmName = smResultsEntry.getKey();
         final Object  result = smResultsEntry.getValue();
         if ( result instanceof Map[] )
           jvmNameToAttrMap.put( jvmName, collate( (Map<ObjectName,AttributeList>[]) result ) );
         else if ( result instanceof Throwable )
           jvmNameToExceptionMap.put( jvmName, (Throwable) result );
       }
     }
   }
 }

 private static boolean  containsResultsForMs( final Map<String,Map<String,Map<String,Object>>> smToMsAttrMap, final String methodServerName )
 {
   if ( smToMsAttrMap != null )
     for ( Map<String,Map<String,Object>> msToAttrMap : smToMsAttrMap.values() )
       if ( msToAttrMap.containsKey( methodServerName ) )
         return ( true );
   return ( false );
 }

 private static final int  MILLIS_PER_SECOND = 1000;
 private static final int  MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
 private static final int  MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
 private static final int  MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;

 // render millisecond duration into days, hours, minutes, and seconds
 private static String  renderMillis( final long millis, final ResourceBundle resourceBundle, final Locale locale )
 {
   final long  days = millis / MILLIS_PER_DAY;
   long  remainder = millis % MILLIS_PER_DAY;
   final long  hours = remainder / MILLIS_PER_HOUR;
   remainder %= MILLIS_PER_HOUR;
   final long  minutes = remainder / MILLIS_PER_MINUTE;
   remainder %= MILLIS_PER_MINUTE;
   final long  seconds = remainder / MILLIS_PER_SECOND;
   remainder %= MILLIS_PER_SECOND;
   final String  msgFormat = resourceBundle.getString( ( days > 0 ) ? serverStatusResource.TIME_DURATION_FORMAT_W_DAYS
                                                                    : serverStatusResource.TIME_DURATION_FORMAT_WO_DAYS );
   final DecimalFormat  twoDigitFormat = new DecimalFormat( "00" );
   return ( MBeanUtilities.formatMessage( msgFormat,
                                          NumberFormat.getNumberInstance( locale ).format( days ),  // in case # of days goes into thousands, use proper formatting...
                                          twoDigitFormat.format( hours ),
                                          twoDigitFormat.format( minutes ),
                                          twoDigitFormat.format( seconds ),
                                          remainder ) );
 }

 private static final double  BYTES_PER_MB_AS_DBL = 1024.0 * 1024.0;

 // render free vs. total physical or swap memory; these items may be null as they're Sun-specific features
 private static String  renderSysMemInfo( final Map<String,Object> dataMap,
                                          final String freeMemItemName, final String totalMemItemName,
                                          final DecimalFormat decimalFormat, final ResourceBundle resourceBundle )
 {
   final Long  freeMem = (Long) dataMap.get( freeMemItemName );
   if ( freeMem != null )
   {
     final StringBuilder  sb = new StringBuilder();
     sb.append( decimalFormat.format( freeMem / BYTES_PER_MB_AS_DBL ) );
     sb.append( resourceBundle.getString( serverStatusResource.MB ) );
     final Long  totalMem = (Long) dataMap.get( totalMemItemName );
     if ( totalMem != null )
     {
       sb.append( " (" );
       sb.append( decimalFormat.format( 100.0 * (double)freeMem / (double)totalMem ) );
       sb.append( decimalFormat.getDecimalFormatSymbols().getPercent() );
       sb.append( ')' );
     }
     return ( sb.toString() );
   }
   else
     return ( null );
 }

 private static ObjectName  newObjectName( final String objectNameString )
 {
   try
   {
     return ( new ObjectName( objectNameString ) );
   }
   catch ( Exception e )
   {
     if ( e instanceof RuntimeException )
       throw (RuntimeException) e;
     throw new RuntimeException( e );
   }
 }

 private static String   xmlEscape( final char ch )
 {
   final String  replacement = MBeanUtilities.getXmlReplacementString( ch );
   if ( replacement != null )
     return ( replacement );
   return ( new String( new char[] { ch } ) );
 }

 private static String  xmlEscape( final String string )
 {
   return ( MBeanUtilities.xmlEscape( string ) );
 }

 private static String  xmlEscape( final Object object )
 {
   return ( ( object != null ) ? xmlEscape( object.toString() ) : null );
 }
 
 private static String  getXmlEscapedString( final ResourceBundle bundle, final String key )
 {
   return ( xmlEscape( bundle.getString( key ) ) );
 }
%>
